from pydantic import BaseModel,field_validator, ConfigDict
from backend.cews.models import RepairOrderPart
from typing import Optional
from django.db.models import Q
from datetime import datetime
from django.utils import timezone

def col_error_message(index: int):
    return f"[{chr(index + 65)}]"

class CmWeeklySummaryQueryIndex(BaseModel):
    serial_no_index: int
    date_time_of_incident: int
    car_no: int
    job_no_work_order_no: int
    history_6m_last_pm_failures: int

    @staticmethod
    def cm_weekly_summary_vaildata(row, query_index: 'CmWeeklySummaryQueryIndex'):
        error_msg = {
            "name": "",
            "row": "",
            "col": ""
        }
        query = Q()
        check_field = CmWeeklySummaryCheckUploadField(
            s_n=row[query_index.serial_no_index].replace("\t",""),
            car = row[query_index.car_no].replace("\t",""),
            j_n = row[query_index.job_no_work_order_no].replace("\t",""),
            mtce_type = row[query_index.history_6m_last_pm_failures].split("on "),
            check_out=row[query_index.history_6m_last_pm_failures].split("on "),
            report_date = row[query_index.date_time_of_incident].replace("\t", "")
            )

        if check_out := check_field.check_out:
            query &= Q(repair_order__check_out__year=check_out.year,
            repair_order__check_out__month=check_out.month,
            repair_order__check_out__day=check_out.day,
            repair_order__check_out__hour=check_out.hour,
            repair_order__check_out__minute=check_out.minute,
            repair_order__check_out__second=check_out.second)
        elif check_out == None:
            error_msg["name"] += "check_out"
            error_msg["col"] += col_error_message(query_index.history_6m_last_pm_failures)
            query &= Q(repair_order__check_out=timezone.now())
        else:
            query &= Q(repair_order__check_out__isnull=True)
        
        if report_date := check_field.report_date:
            query &= Q(repair_order__report_date__istartswith=report_date)
        elif report_date is None:
            error_msg["name"] += "report_date"
            error_msg["col"] += col_error_message(query_index.date_time_of_incident)
            query &= Q(repair_order__report_date="fail")

        query &= Q(serial_no=check_field.s_n,repair_order__location=check_field.car, repair_order__parent_work_order_no=check_field.j_n, repair_order__mtce_type=check_field.mtce_type)
        return query, error_msg


class CmWeeklySummaryCheckUploadField(BaseModel):
    s_n: str | None
    car: str | None
    j_n: str | None
    mtce_type: str | None
    report_date: datetime | str | None
    check_out: datetime | str | None

    @field_validator('report_date', mode='wrap')
    def report_date_process(cls,input_value , handler):
        if not input_value:
            return ""
        try:
            return datetime.strptime(input_value.split(" ")[0],"%d-%b-%y").strftime("%Y-%m-%d")
        except ValueError:
            return None

    @field_validator('check_out', mode='wrap')
    def check_out_process(cls, input_value, handler):
        if len(input_value) == 1:
            # 没有check_out
            return ""
        try:
            return timezone.make_aware(datetime.strptime(input_value[-1], "%d/%m/%Y %H:%M:%S"), timezone.get_current_timezone())
        except ValueError:
            # 输入异常
            return None

    @field_validator('mtce_type', mode='wrap')
    def mtce_type_process(cls, input_value, handler):
        if len(input_value) == 1:
            # 只输入了时间的情况下
            return input_value[0]
        # 输入了两个的情况下
        return input_value[0].split(" ")[1]



class CmWeeklySummaryNotModifiedIndex(BaseModel):
    maintenance_details: int
    repair_details: int


    def upload_cm_weekly_summary_not_field_validata(self, row_data: list, row_count: int, repair_order_part_obj: RepairOrderPart, error_list: list) -> None:
        error_msg = {
            "name": "",
            "col": "",
            "row": str(row_count)
        }
        not_field_data = self.model_dump()
        if not (r_o := repair_order_part_obj.repair_order):
            return None

        not_data = None
        detail_queryset = r_o.repairorderrepairdetails_set.all()
        for name, index in not_field_data.items():
            if name == "maintenance_details":
                data = detail_queryset.first().maintenance_details
                upload_data_raw = row_data[index].split(";")
                if len(upload_data_raw) == 2:
                    upload_data = upload_data_raw[0]
                else:
                    upload_data = ""
            elif name == "repair_details":
                data = detail_queryset.first().repair_details
                upload_data_raw = row_data[index].split(";")
                if len(upload_data_raw) == 2:
                    upload_data = upload_data_raw[1]
                else:
                    upload_data = upload_data_raw[0]
            else:
                upload_data = row_data[index]
                data = getattr(r_o, name, not_data)
            
            if data is not_data:
                continue
            
            if upload_data != data.replace("\n", ""):
                error_msg["name"] += name
                error_msg["col"] += col_error_message(index)
        if error_msg["name"]:
            error_list.append(f"Please do not modify the data in row {error_msg['row']}, columns error{error_msg['col']}")

class IncidentViewQueryIndex(BaseModel):
    check_out_date_index: int
    check_in_date_index: int
    serial_no_index: int
    stock_code_index: int


    @staticmethod
    def upload_csv_upload_Incident_view_vaildata(row: list, query_index:'IncidentViewQueryIndex') -> (Q, dict):
        error_msg = {
                "name": "",
                "col": "",
                "row": ""
            }
        query = Q()
        check_field = IncidentViewCheckUploadField(check_in=row[query_index.check_in_date_index], check_out=row[query_index.check_out_date_index])
        if (check_in := check_field.check_in) == " ":
            query &= Q(repair_order__check_in__isnull=True)
        elif check_in is None:
            error_msg["name"] += "Check In Date"
            error_msg["col"] += f"[{query_index.check_in_date_index + 1}-{chr(query_index.check_in_date_index + 65)}]"
            query &= Q(repair_order__check_in=datetime.now())
        else:
            query &= Q(repair_order__check_in__year=check_in.year,
            repair_order__check_in__month=check_in.month,
            repair_order__check_in__day=check_in.day,
            repair_order__check_in__hour=check_in.hour,
            repair_order__check_in__minute=check_in.minute,
            repair_order__check_in__second=check_in.second)

        if (check_out := check_field.check_out) == " ":
            query &= Q(repair_order__check_out__isnull=True)
        elif check_out is None:
            error_msg["name"] += ";Check out date"
            error_msg["col"] += f",[{query_index.check_in_date_index + 1}-{chr(query_index.check_out_date_index + 65)}]"
            query &= Q(repair_order__check_out=datetime.now())
        else:
            query &= Q(repair_order__check_out__year=check_out.year,
            repair_order__check_out__month=check_out.month,
            repair_order__check_out__day=check_out.day,
            repair_order__check_out__hour=check_out.hour,
            repair_order__check_out__minute=check_out.minute,
            repair_order__check_out__second=check_out.second)

        s_c = row[query_index.stock_code_index].replace("\t", "")
        s_n = row[query_index.serial_no_index].replace("\t", "")
        query &= Q(stock_code=s_c, serial_no=s_n)
        return query, error_msg


class IncidentViewNotModifiedIndex(BaseModel):
    parent_work_order_no: int   # line_work_order
    mtce_type: int              # worder_nature_level
    report_date: int
    location: int
    detail_description: int     # equipment_desc
    workgroup: int
    test_result: int

    def upload_incident_view_not_field_vaildata(self, row_data: list,row_count: int,repair_order_part_obj: RepairOrderPart, error_list: list):
        error_msg = {
            "name": "",
            "col": "",
            "row": str(row_count)
        }
        not_field_data = self.model_dump()
        if not (r_o := repair_order_part_obj.repair_order):
            return None

        not_data = "notdata"
        for name, index in not_field_data.items():
            upload_data:str = row_data[index]

            if name == "detail_description":
                data = getattr(repair_order_part_obj, name, not_data)
            elif name == "test_result":
                if detail_queryset := r_o.repairorderrepairdetails_set:
                    data = getattr(detail_queryset.first(), name) #detail_queryset.first().test_result
            else:
                data = getattr(r_o, name, not_data)

            if data is not_data:
                continue         

            if name == "report_date":
                upload_data_split = upload_data.split(" ")
                upload_data=upload_data_split[0].replace("/","-")
                date_process_list = upload_data.split("-")
                if len(date_process_list) == 3:
                    if len(date_process_list[1]) == 1:
                        date_process_list[1] = "0" + date_process_list[1]
                    if len(date_process_list[2]) == 1:
                        date_process_list[2] = "0" + date_process_list[2]
                    upload_data = "-".join(date_process_list)

                data = data.split(" ")
                data = data[0]

            if upload_data != data:
                error_msg["name"] += name
                error_msg["col"] += col_error_message(index)
            
        if error_msg["name"]:
            error_list.append(f"Please do not modify the data in row {error_msg['row']}, columns error{error_msg['col']}")


class IncidentViewCheckUploadField(BaseModel):
    check_in: datetime | str
    check_out: datetime | str

    @field_validator('check_in', mode='wrap')
    def check_in_process(cls, input_value, handler):
        if input_value == " ":
            return input_value
        try:
            return timezone.make_aware(datetime.strptime(input_value.replace("\t", ""), "%Y/%m/%d %H:%M:%S"), timezone.get_current_timezone())
        except ValueError:
            return None
    

    @field_validator('check_out', mode='wrap')
    def check_out_process(cls, input_value, handler):
        if input_value == " ":
            return input_value
        try:
            return timezone.make_aware(datetime.strptime(input_value.replace("\t", ""), "%Y/%m/%d %H:%M:%S"), timezone.get_current_timezone())
        except ValueError:
            return None





class IncidentViewDetailBase(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    test_result: str
    maintenance_details: str
    repair_details: str


class IncidentViewRepairOrderBase(BaseModel):
    model_config = ConfigDict(from_attributes=True)
    parent_work_order_no: str
    mtce_type: str
    report_date: str
    location: str
    failure_symptom: str
    remark:  str
    delay_i:  str
    delay_a:  str
    work_order_no: str 
    check_in:  datetime | None
    check_out:  datetime | None
    workgroup:  str
    repairorderrepairdetails_set: IncidentViewDetailBase | None

    @field_validator('repairorderrepairdetails_set', mode='wrap')
    def repairorderrepairdetails_set_process(cls, input_value, handler):
        if input_value != None:
            data = input_value.first()
            return handler(data)
        return None


class IncidentViewRepairOrderPartBase(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    repair_order: IncidentViewRepairOrderBase | None
    serial_no: str
    stock_code: str
    detail_description: str


class IncidentViewBase(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    repair_order_part: Optional[IncidentViewRepairOrderPartBase] = None

